//////////////////////////////////////////////
//                                          //
//          Alexander K. Haley's            //
//            Space Warz Game               //
//    (For Prototype Hardware, w/o CPU)     //
//                                          //
//                Build #1                  //
//           Last edit 5/1/2020             //
//        Originally made 5/1/2020          //
//                                          //
//        (c) Alexander K. Haley            //
//                  of                      //
//            Kincaid Arcade                //
//                                          //
//////////////////////////////////////////////

//One thing I would certainly change if I did this again would be to rearrange pins to facilitate port manipulation.
//Also use a DUE.

//Began writing a method of testing the switches.

//address pins: a0-a10 = pin 22-32
//data pins: q0-q11 = pin 38-39
//misc pins:
//  processorready = pin 32
//  processoroverride = pin 7
//  writeenable = pin 34
//  outputenable = pin 35
//  chipselect = pin 36
//  framecomplete = pin 37  INPUT
//LED debugging pins:
//  ledone = pin 12
//  ledtwo = pin 11
//  ledthree = pin 10
//  errorled = pin 9

byte azero  = 22;
byte aone   = 23;
byte atwo   = 24;
byte athree = 25;
byte afour  = 26;
byte afive  = 27;
byte asix   = 28;
byte aseven = 29;
byte aeight = 30;
byte anine  = 31;
byte aten   = 32;

//data pins
byte qzero     = 38;
byte qone      = 39;
byte qtwo      = 40;
byte qthree    = 41;
byte qfour     = 42;
byte qfive     = 43;
byte qsix      = 44;
byte qseven    = 45;
byte qeight    = 46;
byte qnine     = 47;
byte qten      = 48;
byte qeleven   = 49;
//byte qtwelve   = 50; Technically, they aren't ever used...
//byte qthirteen = 51;
//byte qfourteen = 52;
//byte qfifteen  = 53;

//switch input pins
byte ptwofire   = A0; 
byte ptwothrust = A1;
byte ptwohyperspace = A2;
byte ptworight  = A3;
byte ptwoleft   = A4;

byte startbutton = A8;

byte ponefire   = A9;
byte ponethrust = A10;
byte ponehyperspace = A11; 
byte poneright  = A12;
byte poneleft   = A13;


//misc. pins
byte processorready = 33;

byte writeenable    = 34;
byte outputenable   = 35;
byte chipselect     = 36;
byte framecomplete  = 37;

byte processoroverride = 7;

byte ledone = 12;
byte ledtwo = 11;
byte ledthree = 10;
byte errorled = 9;

//Frame Buffer
//                  1     2    3    4     5     6    7    8    9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   33   34   35   36   37   38   39   40   41   42   43   44   45   46   47   48   49   50   51   52   53   54   55   56   57   58   59   60   61   62   63   64   65   66   67   68   69   70   71   72   73   74   75   76   77   78   79   80   81   82   83   84   85   86   87   88   89   90   91   92   93   94   95   96
int xcoords[97] = {-96,  -96, 927, 927,  -96,  0,   64,  64,  0,   32,  96,  736, 800, 832, 768, 768, 832, 800, 736, 96,  32,  144, 144, 208, 208, 144, 208, 240, 240, 304, 304, 240, 272, 304, 400, 336, 336, 400, 432, 432, 496, 496, 432, 496, 528, 528, 560, 592, 592, 560, 528, 688, 624, 624, 688, 682, 624, 672, 704, 736, 736, 704, 672, 672, 640, 576, 608, 608, 640, 576, 544, 544, 480, 480, 544, 480, 448, 384, 384, 448, 352, 352, 288, 288, 256, 192, 224, 224, 256, 192, 160, 96,  160, 96,  96,  96};
int ycoords[97] = {-177, 591, 591, -177, -177, 32,  96,  320, 384, 416, 352, 352, 416, 384, 320, 96,  32,  0,   64,  64,  0,   96,  192, 192, 96,  144, 144, 96,  192, 192, 144, 144, 144, 96,  96,  96,  192, 192, 96,  192, 192, 96,  144, 144, 96,  192, 192, 160, 128, 96,  96,  96,  96,  192, 192, 144, 144, 224, 224, 256, 288, 320, 320, 224, 224, 224, 224, 320, 320, 320, 224, 320, 320, 224, 272, 272, 224, 224, 320, 320, 320, 224, 320, 224, 224, 224, 224, 320, 320, 320, 320, 272, 226, 224, 320, 320};
int zvalues[97] = {0,    15,  15,  15,    15,  0,   15,  15,  15,  0,   15,  15,  15,  0,   15,  15,  15,  0,   15,  15,  15,  0,   15,  15,  15,  0,   15,  0,   15,  15,  15,  15,  0,   15,  0,   15,  15,  15,  0,   15,  15,  15,  0,   15,  0,   15,  15,  15,  15,  15,  15,  0,   15,  15,  15,  0,   15,  0,   15,  15,  15,  15,  15,  15,  0,   15,  0,   15,  0,   15,  0,   15,  15,  15,  0,   15,  0,   15,  15,  15,  0,   15,  15,  15,  0,   15,  0,   15,  0,   15,  0,   15,  15,  0,   15,   128};
//I have a couple of negatives to counteract the x+96 and y+304 that happens later in the program.
//z is brightness 0-127 (8th bit signals end of frame data)
//a zero for z will have the graphics card "skip" to the location, rather than draw. Anything greater than 128 pauses graphics card.

//variables
int currentaddress  = 1;
int internaladdress = 0;
int mathaddress     = 0;

int currentdata = 0;
int mathdata    = 0;

byte bank = 0;
byte portdata = 0;

byte address[12];
byte data[12];

byte lastswitchstates[12];
byte currentswitchstates[12];
byte hitswitches[12];


void setup() {
Serial.begin(9600);

//The ports on the Mega are weird...
DDRA = DDRA | B11111111;
DDRB = DDRB | B01110000;
DDRC = DDRC | B11111110;
DDRD = DDRD | B10000000;
DDRG = DDRG | B00000111;
DDRH = DDRH | B01010000;
DDRL = DDRL | B11111111;

pinMode(ponefire,INPUT);
pinMode(ponethrust,INPUT);
pinMode(ponehyperspace,INPUT);
pinMode(poneright,INPUT);
pinMode(poneleft,INPUT);

pinMode(startbutton,INPUT);

pinMode(ptwofire,INPUT);
pinMode(ptwothrust,INPUT);
pinMode(ptwohyperspace,INPUT);
pinMode(ptworight,INPUT);
pinMode(ptwoleft,INPUT);

/*
digitalWrite(chipselect,LOW);
digitalWrite(outputenable,HIGH); //Make sure we're in high impedance mode.
digitalWrite(writeenable,HIGH);

//load both frame buffers with data
digitalWrite(ledone,HIGH);
for(int x=0; x<289; x++)
  {
    computeaddress();
    computedata();
    writedata();
    currentaddress++;
  }
initiateprocessoroverride();
currentaddress = 1;
internaladdress = 0;
bank = 0;

digitalWrite(ledone,LOW);
digitalWrite(ledtwo,HIGH);
for(int x=0; x<289; x++)
  {
    computeaddress();
    computedata();
    writedata();
    currentaddress++;
  }
vgenchecker();
currentaddress = 1;
internaladdress = 0;
bank = 0;
digitalWrite(ledtwo,LOW);
digitalWrite(ledthree,HIGH);
*/
}

void loop() {
  // put your main code here, to run repeatedly:
//toggle active frame buffer each time the vgen sends FRAMECOMPLETE.
//delay(16); //Makes the amount of frames closer to 60.
//vgenchecker();

readswitches();
//apply game logic
//manipulate game objects xy
//write game objects xy to ram
//Check time to complete to millis watchdog. - Light LED if too slow.

}

void computeaddress()
{
  //split address into zeros and ones
  mathaddress = currentaddress;
  
  if(mathaddress >= 1024)
    {
      //digitalWrite(aten,HIGH); 
      PORTC = PORTC | B00100000;
      mathaddress -= 1024; 
    }
  else
    {
      //digitalWrite(aten,LOW);
      PORTC = PORTC & B11011111;
    }
    
  if(mathaddress >= 512)
    {
      //digitalWrite(anine,HIGH); 
      PORTC = PORTC | B01000000; 
      mathaddress -= 512; 
    }
  else
    {
      //digitalWrite(anine,LOW);
      PORTC = PORTC & B10111111;
    }
    
  if(mathaddress >= 256)
    {
      //digitalWrite(aeight,HIGH);  
      PORTC = PORTC | B10000000;
      mathaddress -= 256; 
    }
  else
    {
      //digitalWrite(aeight,LOW);
      PORTC = PORTC & B01111111; 
    }

  portdata = mathaddress;
  PORTA = portdata;
}

void computedata()
{
  if(bank == 3)
    {
      bank = 0;  
      internaladdress ++;
    }
  
  if(bank == 0) //x bank
    {
      currentdata = xcoords[internaladdress];
      currentdata += 96;
    }
  else if(bank == 1) //y bank
    {
      currentdata = ycoords[internaladdress];
      currentdata += 304;
    }
  else if(bank == 2) //zbank
    {
      currentdata = zvalues[internaladdress];
    }

  mathdata = currentdata;

  if(mathdata >= 2048)
    {
      //digitalWrite(qeleven,HIGH); 
      PORTL = PORTL | B00000001;
      mathdata -= 2048; 
    }
  else
    {
      //digitalWrite(qeleven,LOW);
      PORTL = PORTL & B11111110;
    }

  if(mathdata >= 1024)
    {
      //digitalWrite(qten,HIGH); 
      PORTL = PORTL | B00000010;
      mathdata -= 1024; 
    }
  else
    {
      //digitalWrite(qten,LOW);
      PORTL = PORTL & B11111101;
    }
    
  if(mathdata >= 512)
    {
      //digitalWrite(qnine,HIGH);
      PORTL = PORTL | B00000100;  
      mathdata -= 512; 
    }
  else
    {
      //digitalWrite(qnine,LOW);
      PORTL = PORTL & B11111011;
    }
    
  if(mathdata >= 256)
    {
      //digitalWrite(qeight,HIGH);  
      PORTL = PORTL | B00001000;
      mathdata -= 256; 
    }
  else
    {
      //digitalWrite(qeight,LOW);
      PORTL = PORTL & B11110111;
    }
    
  if(mathdata >= 128)
    {
      //digitalWrite(qseven,HIGH);  
      PORTL = PORTL | B00010000;
      mathdata -= 128; 
    }
  else
    {
      //digitalWrite(qseven,LOW);
      PORTL = PORTL & B11101111;
    }
    
  if(mathdata >= 64)
    {
      //digitalWrite(qsix,HIGH);  
      PORTL = PORTL | B00100000;
      mathdata -= 64; 
    }
  else
    {
      //digitalWrite(qsix,LOW);
      PORTL = PORTL & B11011111;
    }
    
  if(mathdata >= 32)
    {
      //digitalWrite(qfive,HIGH); 
      PORTL = PORTL | B01000000; 
      mathdata -= 32; 
    }
  else
    {
      //digitalWrite(qfive,LOW);
      PORTL = PORTL & B10111111;
    }
    
  if(mathdata >= 16)
    {
      //digitalWrite(qfour,HIGH);  
      PORTL = PORTL | B10000000;
      mathdata -= 16; 
    }
  else
    {
      //digitalWrite(qfour,LOW);
      PORTL = PORTL & B01111111;
    }
    
  if(mathdata >= 8)
    {
      //digitalWrite(qthree,HIGH);  
      PORTG = PORTG | B00000001;
      mathdata -= 8; 
    }
  else
    {
      //digitalWrite(qthree,LOW);
      PORTG = PORTG & B11111110;
    }
    
  if(mathdata >= 4)
    {
      //digitalWrite(qtwo,HIGH); 
      PORTG = PORTG | B00000010; 
      mathdata -= 4; 
    }
  else
    {
      //digitalWrite(qtwo,LOW);
      PORTG = PORTG & B11111101;
    }
    
  if(mathdata >= 2)
    {
      //digitalWrite(qone,HIGH);  
      PORTG = PORTG | B00000100;
      mathdata -= 2; 
    }
  else
    {
      //digitalWrite(qone,LOW);
      PORTG = PORTG & B11111011;
    }
    
  if(mathdata >= 1)
    {
      //digitalWrite(qzero,HIGH);  
      PORTD = PORTD | B10000000;
      mathdata -= 1; 
    }
  else
    {
      //digitalWrite(qzero,LOW);
      PORTD = PORTD & B01111111;
    }

  if(mathdata != 0)
    {
      //digitalWrite(errorled,HIGH);  
    }
}

void writedata()
{
  //digitalWrite(writeenable,LOW);
  //digitalWrite(writeenable,HIGH);
  PORTC = PORTC & B11110111; //why does this work? Well, each port manipulation takes 4.9 us, which is 4900 nanoseconds.
  PORTC = PORTC | B00001000; //That may seem like a long time, but if you consider that each digitalWrite takes up to 2 milliseconds...
  bank ++;
}

void initiateprocessoroverride()
{
  //digitalWrite(processoroverride, HIGH);
  PORTH = PORTH | B00010000;
  //digitalWrite(processorready, HIGH);
  PORTC = PORTC | B00010000;
  //digitalWrite(processoroverride, LOW);
  PORTH = PORTH & B11101111;
  //digitalWrite(processorready, LOW);  
  PORTC = PORTC & B11101111;
}

void vgenchecker()
{
  while(digitalRead(framecomplete) == LOW)
    {
      delayMicroseconds(1);  
    }
  if(digitalRead(framecomplete) == HIGH)
    {
      //digitalWrite(processorready,HIGH);
      PORTC = PORTC | B00010000;
      //digitalWrite(processorready,LOW);
      PORTC = PORTC & B11101111;
    }  
}

void readswitches()
{
  currentswitchstates[0] = digitalRead(ptwofire);
  currentswitchstates[1] = digitalRead(ptwothrust);
  currentswitchstates[2] = digitalRead(ptwohyperspace);
  currentswitchstates[3] = digitalRead(ptworight);
  currentswitchstates[4] = digitalRead(ptwoleft);

  currentswitchstates[5] = digitalRead(startbutton);
  
  currentswitchstates[6] = digitalRead(ponefire);
  currentswitchstates[7] = digitalRead(ponethrust);
  currentswitchstates[8] = digitalRead(ponehyperspace);
  currentswitchstates[9] = digitalRead(poneright);
  currentswitchstates[10] = digitalRead(poneleft);

  for(byte x=0; x<11; x++)
    {
      if(currentswitchstates[x] == 1 && lastswitchstates[x] == 0)
        {
          hitswitches[x] = 1;
        }
      else
        {
          hitswitches[x] = 0;  
        }
    }

  for(byte x=0; x<11; x++)
    {
      lastswitchstates[x] = currentswitchstates[x];  
    }

  if(hitswitches[0] == 1) //P2 Fire button
    {
      Serial.println("P2 fired");  
    }
  if(hitswitches[1] == 1) //P2 Thrust
    {
      Serial.println("P2 applied thrust");  
    }
  if(hitswitches[2] == 1) //P2 Hyperspace
    {
      Serial.println("P2 entered hyperspace");  
    }
  if(hitswitches[3] == 1) //P2 Right
    {
      Serial.println("P2 turned right");  
    }
  if(hitswitches[4] == 1) //P2 Left
    {
      Serial.println("P2 turned left");  
    }
  if(hitswitches[5] == 1) //Start
    {
      Serial.println("The start button was pressed.");  
    }
  if(hitswitches[6] == 1) //P1 Fire
    {
      Serial.println("P1 Fired");  
    }
  if(hitswitches[7] == 1) //P1 Thrust
    {
      Serial.println("P1 applied thrust");  
    }
  if(hitswitches[8] == 1) //P1 Hyperspace
    {
      Serial.println("P1 hyperspaced");  
    }
  if(hitswitches[9] == 1) //P1 Right
    {
      Serial.println("P1 turned right");  
    }
  if(hitswitches[10] == 1) //P1 Left
    {
      Serial.println("P1 turned left");  
    }
  
}
